# your_app/views.py

from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
import psutil, platform, os, time, subprocess, json
import platform, subprocess, shlex
from .utils import *
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.permissions import IsAuthenticated
import whois
import socket
from ipwhois import IPWhois
from ipwhois.exceptions import IPDefinedError
import paramiko
from rest_framework import status
from django.db import models
from django.db.models.functions import ExtractHour
from .models import *



class SystemStatusView(APIView):
    """
    返回系统状态：
      - 共通：平台、CPU、内存、磁盘、网络、传感器（温度/风扇/电池/GPU）、启动时长
      - macOS 特有：macOS 版本、CPU 型号、硬盘格式
      - Ubuntu 特有：发行版信息、APT 包数、容器检测、EC2 Metadata
    通过 hasattr 和 try/except 保证在方法不可用时不抛异常。
    """
    permission_classes = [IsAuthenticated]
    def get(self, request):
        data = {}

        # --- 1. 共通指标 ---

        # 1.1 平台基础信息
        system = platform.system()
        data['system'] = {
            "name": system,
            "release": platform.release(),
            "version": platform.version(),
            "architecture": platform.machine(),
            "hostname": platform.node(),
        }

        # 1.2 CPU 信息
        data['cpu'] = {
            "total_percent": psutil.cpu_percent(interval=1),
            "per_core_percent": psutil.cpu_percent(percpu=True, interval=1),
            "cores_physical": psutil.cpu_count(logical=False),
            "cores_total": psutil.cpu_count(logical=True),
            "stats": psutil.cpu_stats()._asdict() if hasattr(psutil, "cpu_stats") else {},
            "load_avg": psutil.getloadavg() if hasattr(psutil, "getloadavg") else (None, None, None),
        }

        # 1.3 内存与交换分区
        data['memory'] = psutil.virtual_memory()._asdict()
        data['swap'] = psutil.swap_memory()._asdict()

        # 1.4 磁盘信息
        partitions = psutil.disk_partitions(all=False)
        disk_usage = {}
        for p in partitions:
            try:
                disk_usage[p.mountpoint] = psutil.disk_usage(p.mountpoint)._asdict()
            except PermissionError:
                disk_usage[p.mountpoint] = {"error": "Permission denied"}
        data['disk'] = {
            "partitions": [p._asdict() for p in partitions],
            "usage": disk_usage,
            "io_counters": psutil.disk_io_counters()._asdict() if hasattr(psutil, "disk_io_counters") else {},
        }

        # 1.5 网络信息
        data['network'] = {
            "io_counters": psutil.net_io_counters()._asdict(),
            "interfaces": {
                name: [addr._asdict() for addr in addrs]
                for name, addrs in psutil.net_if_addrs().items()
            },
            "stats": {
                name: stat._asdict()
                for name, stat in psutil.net_if_stats().items()
            },
        }

        # 1.6 传感器：温度 / 风扇 / 电池 / GPU
        sensors = {}
        if hasattr(psutil, "sensors_temperatures"):
            sensors["temperatures"] = {
                k: [t._asdict() for t in v]
                for k, v in psutil.sensors_temperatures().items()
            }
        if hasattr(psutil, "sensors_fans"):
            sensors["fans"] = {
                k: [f._asdict() for f in v]
                for k, v in psutil.sensors_fans().items()
            }
        if hasattr(psutil, "sensors_battery"):
            batt = psutil.sensors_battery()
            sensors["battery"] = batt._asdict() if batt else {}
        # GPU 信息（可选）
        try:
            import GPUtil
            sensors["gpus"] = [{
                'id': g.id,
                'name': g.name,
                'load': g.load,
                'memoryUtil': g.memoryUtil,
                'temperature': g.temperature
            } for g in GPUtil.getGPUs()]
        except ImportError:
            sensors["gpus"] = []
        data['sensors'] = sensors

        # 1.7 启动时长
        boot = psutil.boot_time()
        data['uptime'] = {
            "boot_time": boot,
            "uptime_seconds": time.time() - boot
        }

        # --- 2. 平台特有指标 ---

        extras = {}

        if system == "Darwin":
            # macOS：版本、CPU 型号、硬盘格式
            extras['macos_version'] = platform.mac_ver()[0]
            try:
                cpu_brand = subprocess.check_output(
                    ["sysctl", "-n", "machdep.cpu.brand_string"]
                ).decode().strip()
            except Exception:
                cpu_brand = None
            extras['cpu_brand'] = cpu_brand

            try:
                info = subprocess.check_output(
                    ["diskutil", "info", "-all", "-json"]
                ).decode()
                disk_json = json.loads(info)
                first = disk_json.get("AllDisksAndPartitions", [])[0]
                extras['disk_format'] = first.get("Content")
            except Exception:
                extras['disk_format'] = None

        elif system == "Linux":
            # Ubuntu 发行版信息
            try:
                with open("/etc/os-release") as f:
                    osr = {}
                    for line in f:
                        if "=" in line:
                            k, v = line.rstrip().split("=", 1)
                            osr[k] = v.strip('"')
                extras['distro_name']    = osr.get("NAME")
                extras['distro_version'] = osr.get("VERSION_ID")
            except Exception:
                extras['distro_name'] = extras['distro_version'] = None

            # APT 包数
            try:
                dpkg = subprocess.check_output(
                    ["dpkg-query", "-f", "${binary:Package}\n", "-W"]
                ).decode().splitlines()
                extras['installed_packages_count'] = len(dpkg)
            except Exception:
                extras['installed_packages_count'] = None

            # Docker 容器检测
            extras['in_docker'] = os.path.exists("/.dockerenv") or any(
                "docker" in c for c in open("/proc/1/cgroup", errors='ignore')
            )

        data['extras'] = extras
        return Response(data)


class FirewallStatusViewSet(viewsets.ViewSet):
    """
    返回防火墙状态信息：
    - Ubuntu: UFW状态和规则
    - macOS: PF状态和规则
    """
    permission_classes = [IsAuthenticated]

    def _run_ufw_command(self, command):
        """运行UFW命令并返回结果"""
        try:
            # 在macOS上使用sudo执行pfctl命令
            if platform.system() == 'Darwin' and 'pfctl' in command:
                # 使用 -n 参数避免密码提示
                command = f'sudo -n {command}'
            
            result = subprocess.run(
                command,
                shell=True,
                capture_output=True,
                text=True,
                check=True,
                timeout=5  # 添加5秒超时
            )
            return True, result.stdout.strip()
        except subprocess.TimeoutExpired:
            return False, '命令执行超时'
        except subprocess.CalledProcessError as e:
            if 'sudo: no tty present and no askpass program specified' in e.stderr:
                return False, '需要配置sudo无密码执行权限'
            return False, f'命令执行失败: {e.stderr}'
        except Exception as e:
            return False, f'发生错误: {str(e)}'

    def list(self, request):
        system = platform.system()
        if system == 'Linux':
            # 检查UFW是否安装
            ufw_installed = os.path.exists('/usr/sbin/ufw')
            if not ufw_installed:
                return Response({
                    'status': 'error',
                    'message': 'UFW未安装',
                    'system': system
                })

            # 获取UFW状态
            status_success, status_output = self._run_ufw_command('sudo ufw status')
            if not status_success:
                return Response({
                    'status': 'error',
                    'message': status_output,
                    'system': system
                })

            # 获取详细规则
            rules_success, rules_output = self._run_ufw_command('sudo ufw status verbose')
            if not rules_success:
                return Response({
                    'status': 'error',
                    'message': rules_output,
                    'system': system
                })

            # 解析状态输出
            status_lines = status_output.split('\n')
            is_active = 'Status: active' in status_output

            # 解析规则
            rules = []
            for line in status_lines:
                if 'ALLOW' in line or 'DENY' in line:
                    parts = line.split()
                    if len(parts) >= 3:
                        rule = {
                            'port': parts[0],
                            'action': parts[1],
                            'source': parts[2]
                        }
                        rules.append(rule)

            return Response({
                'status': 'success',
                'system': system,
                'firewall': 'UFW',
                'is_active': is_active,
                'status_output': status_output,
                'rules': rules,
                'verbose_output': rules_output
            })

        elif system == 'Darwin':
            try:
                # 首先尝试不使用sudo获取状态
                pf_success, pf_output = self._run_ufw_command('pfctl -s info')
                if not pf_success:
                    return Response({
                        'status': 'error',
                        'message': pf_output,
                        'system': system,
                        'solution': '请确保已配置sudo无密码执行权限，或使用root用户运行应用'
                    })

                # 获取PF规则
                pf_rules_success, pf_rules_output = self._run_ufw_command('pfctl -sr')
                if not pf_rules_success:
                    return Response({
                        'status': 'error',
                        'message': pf_rules_output,
                        'system': system,
                        'solution': '请确保已配置sudo无密码执行权限，或使用root用户运行应用'
                    })

                return Response({
                    'status': 'success',
                    'system': system,
                    'firewall': 'PF',
                    'is_active': 'Status: Enabled' in pf_output,
                    'status_output': pf_output,
                    'rules_output': pf_rules_output
                })
            except Exception as e:
                return Response({
                    'status': 'error',
                    'message': f'执行失败: {str(e)}',
                    'system': system,
                    'solution': '请确保已配置sudo无密码执行权限，或使用root用户运行应用'
                })

        else:
            return Response({
                'status': 'error',
                'message': f'不支持的操作系统: {system}',
                'system': system
            })
    

class PortScanViewSet(viewsets.ViewSet):
    permission_classes = [IsAuthenticated]

    @method_decorator(csrf_exempt)
    def list(self, request):
        # 获取参数
        host = request.GET.get('host', '127.0.0.1')
        start_port = int(request.GET.get('start_port', 20))
        end_port = int(request.GET.get('end_port', 1024))
        timeout = float(request.GET.get('timeout', 0.5))
        common = request.GET.get('common', 'false').lower() == 'true'

        if end_port < start_port:
            return Response({"error": "end_port must be >= start_port"}, status=400)

        # 支持常见端口扫描
        if common:
            from .utils import COMMON_PORTS
            ports = sorted(COMMON_PORTS.keys())
        else:
            ports = list(range(start_port, end_port + 1))

        scan_result = scan_ports_verbose(host, ports, timeout=timeout)

        open_ports = [
            {"port": r["port"], "service": r["service"]}
            for r in scan_result if r["status"] == "open"
        ]
        closed_ports_count = sum(1 for r in scan_result if r["status"] == "closed")

        return Response({
            "host": host,
            "scanned_range": [ports[0], ports[-1]] if ports else [start_port, end_port],
            "timeout": timeout,
            "open_ports": open_ports,
            "closed_ports_count": closed_ports_count,
            "results": scan_result
        })
    

class WhoisViewSet(viewsets.ViewSet):
    permission_classes = [IsAuthenticated]
    def list(self, request):
        domain = request.GET.get("domain")
        if not domain:
            return Response({"error": "Missing 'domain' parameter"}, status=400)

        try:
            # 判断是否是 IP
            socket.inet_aton(domain)
            is_ip = True
        except socket.error:
            is_ip = False

        try:
            if is_ip:
                # IP 地址查询
                obj = IPWhois(domain)
                res = obj.lookup_rdap()
                result = {
                    "query_type": "ip",
                    "ip": domain,
                    "network_name": res.get("network", {}).get("name"),
                    "country": res.get("network", {}).get("country"),
                    "start_address": res.get("network", {}).get("start_address"),
                    "end_address": res.get("network", {}).get("end_address"),
                    "asn": res.get("asn"),
                    "asn_description": res.get("asn_description"),
                    "org": res.get("network", {}).get("org_handle"),
                    "remarks": res.get("remarks", []),
                    "entities": res.get("entities", []),
                }
            else:
                # 域名查询
                w = whois.whois(domain)
                result = {
                    "query_type": "domain",
                    "domain_name": w.domain_name,
                    "registrar": w.registrar,
                    "creation_date": str(w.creation_date),
                    "expiration_date": str(w.expiration_date),
                    "updated_date": str(w.updated_date),
                    "name_servers": w.name_servers,
                    "status": w.status,
                    "emails": w.emails,
                }
            return Response(result)
        except IPDefinedError:
            return Response({"error": f"{domain} 是保留地址（如 127.0.0.1、私有网段），不能查询 WHOIS。"}, status=400)
        except Exception as e:
            return Response({"error": f"查询失败: {str(e)}"}, status=500)


class DjangoStatusView(APIView):
    permission_classes = [IsAuthenticated]
    def get(self, request):
        from django.conf import settings
        from django.db import connection
        import subprocess
        import pkg_resources
        
        # 获取pip包信息
        try:
            # 方法1：使用pkg_resources获取已安装的包
            installed_packages = [
                {
                    'name': pkg.key,
                    'version': pkg.version
                }
                for pkg in pkg_resources.working_set
            ]
            
            # 方法2：使用pip命令获取详细信息
            pip_list = subprocess.check_output(['pip', 'list', '--format=json']).decode()
            pip_packages = json.loads(pip_list)
            
            pip_info = {
                'installed_packages': installed_packages,
                'pip_list': pip_packages
            }
        except Exception as e:
            pip_info = {
                'error': str(e),
                'installed_packages': [],
                'pip_list': []
            }
        
        # 获取数据库信息
        db_info = {
            'engine': settings.DATABASES['default']['ENGINE'],
            'host': settings.DATABASES['default']['HOST'],
            'port': settings.DATABASES['default']['PORT'],
            'name': settings.DATABASES['default']['NAME'],
        }
        
        # 获取Redis配置
        redis_info = {
            'location': settings.CACHES['default']['LOCATION'],
            'session_location': settings.CACHES['session']['LOCATION']
        }
        
        # 获取JWT配置
        jwt_info = {
            'access_token_lifetime': str(settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME']),
            'refresh_token_lifetime': str(settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'])
        }
        
        # 获取REST Framework配置
        rest_framework_info = {
            'default_pagination_class': settings.REST_FRAMEWORK['DEFAULT_PAGINATION_CLASS'],
            'page_size': settings.REST_FRAMEWORK['PAGE_SIZE']
        }
        
        # 获取已安装的应用列表
        installed_apps = settings.INSTALLED_APPS
        
        # 获取中间件列表
        middleware = settings.MIDDLEWARE
        
        # 获取时区和语言设置
        locale_info = {
            'language_code': settings.LANGUAGE_CODE,
            'time_zone': settings.TIME_ZONE,
            'use_i18n': settings.USE_I18N,
            'use_tz': settings.USE_TZ
        }
        
        # 获取静态文件和媒体文件配置
        static_info = {
            'static_url': settings.STATIC_URL,
            'static_root': settings.STATIC_ROOT,
            'media_url': settings.MEDIA_URL,
            'media_root': settings.MEDIA_ROOT
        }
        
        # 获取CORS配置
        cors_info = {
            'allow_credentials': settings.CORS_ALLOW_CREDENTIALS,
            'allow_all': settings.CORS_ORIGIN_ALLOW_ALL,
            'whitelist': settings.CORS_ORIGIN_WHITELIST,
            'allow_methods': settings.CORS_ALLOW_METHODS,
            'allow_headers': settings.CORS_ALLOW_HEADERS
        }
        
        return Response({
            "status": "ok",
            "debug": settings.DEBUG,
            "allowed_hosts": settings.ALLOWED_HOSTS,
            "database": db_info,
            "redis": redis_info,
            "jwt": jwt_info,
            "rest_framework": rest_framework_info,
            "installed_apps": installed_apps,
            "middleware": middleware,
            "locale": locale_info,
            "static": static_info,
            "cors": cors_info,
            "pip_packages": pip_info
        })


class NetworkScanView(APIView):   
    permission_classes = [IsAuthenticated]
    def get(self, request):
        try:
            devices, local_ip = get_network_devices()
            return Response({
                "status": "success",
                "local_ip": local_ip,
                "devices": devices
            })
        except Exception as e:
            return Response({
                "status": "error",
                "message": str(e)
            }, status=500)
        

class SSHConnectView(APIView):
    permission_classes = [IsAuthenticated]
    def post(self, request):
        try:
            # 获取连接参数
            host = request.data.get('host')
            port = int(request.data.get('port', 22))
            username = request.data.get('username')
            password = request.data.get('password')
            session_id = request.data.get('session_id')
            
            # 参数验证
            if not all([host, username, password]):
                return Response({
                    "status": "error",
                    "message": "缺少必要的连接参数"
                }, status=status.HTTP_400_BAD_REQUEST)
            
            # 创建新会话
            if not session_id:
                session_id = str(time.time())
                success, result = ssh_manager.create_connection(
                    session_id=session_id,
                    host=host,
                    port=port,
                    username=username,
                    password=password
                )
                
                if success:
                    # 测试连接
                    test_success, test_result = ssh_manager.execute_command(session_id, 'pwd')
                    if test_success:
                        return Response({
                            "status": "success",
                            "message": "连接成功",
                            "session_id": session_id
                        })
                    else:
                        ssh_manager.close_connection(session_id)
                        return Response(test_result, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    return Response(result, status=status.HTTP_401_UNAUTHORIZED)
            else:
                # 检查现有会话
                ssh = ssh_manager.get_connection(session_id)
                if not ssh:
                    return Response({
                        "status": "error",
                        "message": "会话已失效，请重新连接"
                    }, status=status.HTTP_401_UNAUTHORIZED)
                
                return Response({
                    "status": "success",
                    "message": "会话有效",
                    "session_id": session_id
                })
                
        except Exception as e:
            return Response({
                "status": "error",
                "message": f"发生错误：{str(e)}"
            }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class SSHCommandView(APIView):
    permission_classes = [IsAuthenticated]
    
    def post(self, request):
        try:
            # 获取连接参数
            host = request.data.get('host')
            port = int(request.data.get('port', 22))
            username = request.data.get('username')
            password = request.data.get('password')
            command = request.data.get('command', '')
            session_id = request.data.get('session_id')

            # 验证必要参数
            if not all([host, port, username, password]):
                return Response({
                    'status': 'error',
                    'message': '缺少必要参数'
                }, status=400)

            # 执行命令
            success, result = execute_ssh_command(
                host=host,
                port=port,
                username=username,
                password=password,
                command=command,  # 直接传递完整命令，不进行分割
                session_id=session_id
            )

            if success:
                return Response({
                    'status': 'success',
                    'output': result.get('output', ''),
                    'error': result.get('error', ''),
                    'exit_status': result.get('exit_status', 0),
                    'session_id': session_id
                })
            else:
                return Response({
                    'status': 'error',
                    'message': result.get('message', '执行失败')
                }, status=500)

        except Exception as e:
            return Response({
                'status': 'error',
                'message': f'执行失败：{str(e)}'
            }, status=500)
    

class APIStatisticsView(APIView):
    """API调用统计视图"""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        # 获取查询参数
        start_date = request.GET.get('start_date')
        end_date = request.GET.get('end_date')
        path = request.GET.get('path')
        method = request.GET.get('method')
        status_code = request.GET.get('status_code')
        user_id = request.GET.get('user_id')

        # 构建查询
        queryset = APICallStatistics.objects.all()

        if start_date:
            queryset = queryset.filter(created_at__gte=start_date)
        if end_date:
            queryset = queryset.filter(created_at__lte=end_date)
        if path:
            queryset = queryset.filter(path__icontains=path)
        if method:
            queryset = queryset.filter(method=method)
        if status_code:
            queryset = queryset.filter(status_code=status_code)
        if user_id:
            queryset = queryset.filter(user_id=user_id)

        # 获取统计数据
        total_calls = queryset.count()
        avg_response_time = queryset.aggregate(avg_time=models.Avg('response_time'))['avg_time']
        
        # 按路径统计
        path_stats = queryset.values('path').annotate(
            count=models.Count('id'),
            avg_time=models.Avg('response_time')
        ).order_by('-count')[:10]

        # 按状态码统计
        status_stats = queryset.values('status_code').annotate(
            count=models.Count('id')
        ).order_by('status_code')

        # 按用户统计
        user_stats = queryset.values('user__username').annotate(
            count=models.Count('id'),
            avg_time=models.Avg('response_time')
        ).order_by('-count')[:10]

        # 按时间统计（每小时）
        time_stats = queryset.annotate(
            hour=ExtractHour('created_at')
        ).values('hour').annotate(
            count=models.Count('id')
        ).order_by('hour')

        return Response({
            'total_calls': total_calls,
            'avg_response_time': avg_response_time,
            'path_stats': list(path_stats),
            'status_stats': list(status_stats),
            'user_stats': list(user_stats),
            'time_stats': list(time_stats)
        })
    
